package com.audaque.springboot.foshanupload.core.util;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.util.ReflectUtil;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.stream.Collectors;

/**
 * @Author: ONESTAR
 * @QQ群: 530311074
 * @URL: https://onestar.newstar.net.cn/
 */
public class BeanUtilExtHutool {


    public static List<Object> mergeList(List<Object> sourceList, List<Object> targetList, String idField) {
        if (null == sourceList) {
            return targetList;
        }
        if (null == targetList) {
            return sourceList;
        }
        Map<Object, Object> sourceListGroup = sourceList.stream().collect(Collectors.toMap(t -> ReflectUtil.getFieldValue(t, idField), t -> t));
        targetList.forEach(target -> {
            Object idValue = ReflectUtil.getFieldValue(target, idField);
            Object sourceItem = sourceListGroup.get(idValue);
            if (null != sourceItem) {
                BeanUtil.copyProperties(sourceItem, target, CopyOptions.create().setIgnoreNullValue(true));
                sourceListGroup.remove(idValue);
            }
        });
        targetList.addAll(sourceListGroup.values());
        return targetList;
    }

    public static void copyOnlyNullProperties(Object source, Object target) {
        BeanUtil.copyProperties(source, target, getNonNullPropertyNames(target));
    }

    private static String[] getNonNullPropertyNames(Object target) {
        Set<String> nonEmptyNames = new HashSet<>();
        for (Field field : ReflectUtil.getFields(target.getClass())) {
            if (null != ReflectUtil.getFieldValue(target, field)) {
                nonEmptyNames.add(field.getName());
            }
        }
        String[] result = new String[nonEmptyNames.size()];
        return nonEmptyNames.toArray(result);
    }

    /**
     * source collection 转为target list
     *
     * @param sourceCollection
     * @param targetClass
     * @param consumers
     * @param <S>
     * @param <T>
     * @return
     */
    @SafeVarargs
    public static <S, T> List<T> convert(Collection<S> sourceCollection, Class<T> targetClass, Consumer<T>... consumers) {
        if (CollectionUtils.isEmpty(sourceCollection)) {
            return new ArrayList<>();
        }
        return sourceCollection.stream().map(source -> {
            try {
                return convert(source, targetClass, consumers);
            } catch (InvocationTargetException e) {
                throw new RuntimeException(e);
            } catch (InstantiationException e) {
                throw new RuntimeException(e);
            } catch (IllegalAccessException e) {
                throw new RuntimeException(e);
            }
        }).collect(Collectors.toList());
    }

    /**
     * source collection 转为target list
     *
     * @param sourceCollection
     * @param targetClass
     * @param consumers
     * @param <S>
     * @param <T>
     * @return
     */
    @SafeVarargs
    public static <S, T> List<T> convertCollectionWithBiConsumer(Collection<S> sourceCollection, Class<T> targetClass, BiConsumer<S, T>... consumers) {
        if (CollectionUtils.isEmpty(sourceCollection)) {
            return new ArrayList<>();
        }
        return sourceCollection.stream().map(source -> {
            try {
                return convertWithBiConsumer(source, targetClass, consumers);
            } catch (InvocationTargetException e) {
                throw new RuntimeException(e);
            } catch (InstantiationException e) {
                throw new RuntimeException(e);
            } catch (IllegalAccessException e) {
                throw new RuntimeException(e);
            }
        }).collect(Collectors.toList());
    }

    /**
     * 将source转为target
     *
     * @param source
     * @param targetClass
     * @param consumers
     * @param <S>
     * @param <T>
     * @return
     */
    @SafeVarargs
    public static <S, T> T convert(S source, Class<T> targetClass, Consumer<T>... consumers) throws InvocationTargetException, InstantiationException, IllegalAccessException {
        if (Objects.isNull(source)) {
            return null;
        }


        T target = ReflectUtil.getConstructor(targetClass).newInstance();
        BeanUtil.copyProperties(source, target);
        for (Consumer<T> consumer : consumers) {
            consumer.accept(target);
        }
        return target;

    }

    /**
     * 将source转为target
     *
     * @param source
     * @param target
     * @param targetClass
     * @param consumers
     * @param <S>
     * @param <T>
     * @return
     */
    @SafeVarargs
    public static <S, T> T convert(S source, T target, Class<T> targetClass, Consumer<T>... consumers) throws InvocationTargetException, InstantiationException, IllegalAccessException {
        if (Objects.isNull(source)) {
            return null;
        }

        if (target == null) {
            target = ReflectUtil.getConstructor(targetClass).newInstance();
        }
        BeanUtil.copyProperties(source, target);
        for (Consumer<T> consumer : consumers) {
            consumer.accept(target);
        }

        return target;
    }


    /**
     * 将source转为target
     *
     * @param source
     * @param targetClass
     * @param consumers
     * @param <S>
     * @param <T>
     * @return
     */
    @SafeVarargs
    public static <S, T> T convertWithBiConsumer(S source, Class<T> targetClass, BiConsumer<S, T>... consumers) throws InvocationTargetException, InstantiationException, IllegalAccessException {
        if (Objects.isNull(source)) {
            return null;
        }

        T target = ReflectUtil.getConstructor(targetClass).newInstance();
        BeanUtil.copyProperties(source, target);
        for (BiConsumer<S, T> consumer : consumers) {
            consumer.accept(source, target);
        }

        return target;
    }


}
